package de.htw.praxisprojekt.algo.impl;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

import de.htw.praxisprojekt.AlgoData;
import de.htw.praxisprojekt.Vector2D;
import de.htw.praxisprojekt.algo.LineAlgorithm;
import de.htw.praxisprojekt.data.AlgoPoint;
import de.htw.praxisprojekt.data.draw.DrawLine;
import de.htw.praxisprojekt.data.draw.DrawObject;

public class DouglasPeuckerAgorithm extends LineAlgorithm{

	private JSpinner epsilon;

	@Override
	public String getAlgoName(){
		return "Douglas und Peucker";
	}

	@Override
	public JPanel getOptionPane(){
		JPanel panel=super.getOptionPane();
		panel.add(new JLabel("Toleranzweite"));
		panel.add(epsilon=new JSpinner(new SpinnerNumberModel(60.0,0.0,1000,1)));
		addChangeListenerToSpinner(epsilon);

		panel.add(new JLabel());
		panel.add(new JLabel());

		panel.add(new JLabel());
		panel.add(new JLabel());

		return panel;
	}

	@Override
	public void play(AlgoData algoData,int maxStepIndex){
		super.play(algoData,maxStepIndex);


		if(maxStepIndex == 0)
			return;
		float vEpsilon=((Double)this.epsilon.getValue()).floatValue()*algoData.getScaleFactor();

		List<AlgoPoint> algoPoints=algoData.getAlgoPoints();
		int n=algoPoints.size();
		List<DrawObject> drawObjects=algoData.getDrawObjects();

		List<Vector2D> segmentPoints=new ArrayList<Vector2D>();
		if(algoPoints.size()==0||algoPoints.size()==1)
			return;
		segmentPoints.add(algoPoints.get(0).getPoint());
		for(int i=1;i<n;i++)
			segmentPoints.add(null);
		segmentPoints.set(n-1,algoPoints.get(n-1).getPoint());

		int index=0;
		while(index<maxStepIndex - 1){
			boolean hasChanged=false;

			for(int l=0;l<n-1;l++){
				Vector2D startSegment=segmentPoints.get(l);
				if(startSegment==null)
					continue;

				Vector2D endSegment=null;
				int m=l+1;
				for(;m<n;m++){
					endSegment=segmentPoints.get(m);
					if(endSegment!=null)
						break;
				}

				float maxDistance=0;
				int maxIndex=-1;
				Vector2D maxPoint=null;
				for(int i=l+1;i<m;i++){
					Vector2D point=algoPoints.get(i).getPoint();
					float distance=Vector2D.pointToLineDistance(startSegment,endSegment,point);
					if(distance>maxDistance){
						maxDistance=distance;
						maxIndex=i;
						maxPoint=point;
					}
				}

				if(maxIndex>-1&&maxDistance>vEpsilon){
					segmentPoints.set(maxIndex,maxPoint);
					hasChanged=true;
				}

				l=m-1;
			}

			index++;

			if(!hasChanged)
				break;
		}

		for(int i=0;i<n-1;i++){
			Vector2D startSegment=segmentPoints.get(i);
			if(startSegment==null)
				continue;

			Vector2D endSegment=null;
			int m=i+1;
			for(;m<n;m++){
				endSegment=segmentPoints.get(m);
				if(endSegment!=null)
					break;

			}		
			for(int o = i+1; o<m;o++)
			{
				Vector2D a = startSegment;
				Vector2D b = endSegment;
				Vector2D c = algoPoints.get(o).getPoint();
				Vector2D p = new Vector2D();
				double tl = ((b.x - a.x)*(c.x - a.x) + (b.y - a.y) * (c.y - a.y))/
						   (Math.pow(b.x -a.x, 2)+ Math.pow(b.y - a.y, 2));
				p.x = (float)(a.x + tl * (b.x - a.x));
				p.y = (float)(a.y + tl * (b.y - a.y));	
				drawObjects.add(new DrawLine(p, c).setColor(Color.RED));
				drawObjects.add(new DrawLine(p, startSegment).setColor(Color.BLACK));
				drawObjects.add(new DrawLine(p, endSegment).setColor(Color.BLACK));

			}
			drawObjects.add(new DrawLine(startSegment,endSegment));			
			float[] parLine1=Vector2D.getParallelLineCoord(startSegment.x,startSegment.y,endSegment.x,endSegment.y,vEpsilon);
			float[] parLine2=Vector2D.getParallelLineCoord(startSegment.x,startSegment.y,endSegment.x,endSegment.y,-vEpsilon);
			Vector2D parLine1V1=new Vector2D();
			Vector2D parLine1V2=new Vector2D();
			Vector2D parLine2V1=new Vector2D();
			Vector2D parLine2V2=new Vector2D();
			parLine1V1.x=parLine1[0];
			parLine1V1.y=parLine1[1];
			parLine1V2.x=parLine1[2];
			parLine1V2.y=parLine1[3];
			drawObjects.add(new DrawLine(parLine1V1,parLine1V2).setColor(Color.BLUE));
			parLine2V1.x=parLine2[0];
			parLine2V1.y=parLine2[1];
			parLine2V2.x=parLine2[2];
			parLine2V2.y=parLine2[3];
			drawObjects.add(new DrawLine(parLine2V1,parLine2V2).setColor(Color.BLUE));
		}

		setStepIndex(index);
	}
}
